﻿using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using SharedGenomics.Core;
using SharedGenomics.Workbench.Core;
using SharedGenomics.Workbench.Aspects;
using SharedGenomics.Workbench.Tests.TestObjects;

using Rhino.Mocks;

namespace SharedGenomics.Workbench.Tests.Aspects
{
    [TestClass]
    public class LoginRequiredCallHandlerTests
    {
        private MockRepository mocks;
        private IUnityContainer container;
        private ILoginManager loginManager;
        private ILoginPrompt loginPrompt;

        [TestInitialize]
        public void Setup()
        {
            this.mocks = new MockRepository();
            this.container = new UnityContainer();
            this.loginManager = this.mocks.Stub<ILoginManager>();
            this.loginPrompt = this.mocks.Stub<ILoginPrompt>();

            container.RegisterInstance(this.loginManager);
            container.RegisterInstance(this.loginPrompt);
            container.RegisterType<LoginRequiredCallHandler>();

            //setup interception on container
            container.AddNewExtension<Interception>();
            container.Configure<Interception>().SetDefaultInterceptorFor<LoginRequiredInterceptedClass>(new VirtualMethodInterceptor());
        }

        [TestMethod]
        public void ShouldExecuteVoidMethodWithExistingLogin()
        {
            using (this.mocks.Record())
            {
                this.loginManager.Stub(lm => lm.IsLoggedIn).Return(true);
            }

            using (this.mocks.Playback())
            {
                var testObject = this.container.Resolve<LoginRequiredInterceptedClass>();
                testObject.VoidMethod();

                Assert.IsTrue(testObject.VoidMethodCalled, "Method not called");
            }
        }

        [TestMethod]
        public void ShouldExecuteVoidMethodIfLoginProvided()
        {
            using (this.mocks.Record())
            {
                this.loginManager.Stub(lm => lm.IsLoggedIn).Return(false);
                this.loginPrompt.Stub(p => p.Login()).Return(true);
            }

            using (this.mocks.Playback())
            {
                var testObject = this.container.Resolve<LoginRequiredInterceptedClass>();
                testObject.VoidMethod();

                Assert.IsTrue(testObject.VoidMethodCalled, "Method not called");
            }
        }

        [TestMethod]
        public void ShouldNotExecuteVoidMethod()
        {
            using (this.mocks.Record())
            {
                this.loginManager.Stub(lm => lm.IsLoggedIn).Return(false);
                this.loginPrompt.Stub(p => p.Login()).Return(false);
            }

            using (this.mocks.Playback())
            {
                var testObject = this.container.Resolve<LoginRequiredInterceptedClass>();
                testObject.VoidMethod();

                Assert.IsFalse(testObject.VoidMethodCalled, "Method was called");
            }
        }

        [TestMethod]
        public void ShouldExecuteValueMethodWithExistingLogin()
        {
            using (this.mocks.Record())
            {
                this.loginManager.Stub(lm => lm.IsLoggedIn).Return(true);
            }

            using (this.mocks.Playback())
            {
                var testObject = this.container.Resolve<LoginRequiredInterceptedClass>();
                var value = testObject.MethodWithReturnValue();

                Assert.IsTrue(value.HasValue, "Maybe has no value");
            }
        }

        [TestMethod]
        public void ShouldExecuteValueMethodIfLoginProvided()
        {
            using (this.mocks.Record())
            {
                this.loginManager.Stub(lm => lm.IsLoggedIn).Return(false);
                this.loginPrompt.Stub(p => p.Login()).Return(true);
            }

            using (this.mocks.Playback())
            {
                var testObject = this.container.Resolve<LoginRequiredInterceptedClass>();
                var value = testObject.MethodWithReturnValue();

                Assert.IsTrue(value.HasValue, "Maybe has no value");
            }
        }

        [TestMethod]
        public void ShouldReturnNothing()
        {
            using (this.mocks.Record())
            {
                this.loginManager.Stub(lm => lm.IsLoggedIn).Return(false);
                this.loginPrompt.Stub(p => p.Login()).Return(false);
            }

            using (this.mocks.Playback())
            {
                var testObject = this.container.Resolve<LoginRequiredInterceptedClass>();
                var value = testObject.MethodWithReturnValue();

                Assert.IsFalse(value.HasValue, "Maybe has value");
            }
        }
    }
}
